using System;
using System.Runtime.InteropServices;

namespace PVTLibrary
{
    [StructLayout(LayoutKind.Sequential)] 
    public struct Complex
    {
        public double x;
        public double  y;

        public Complex(double _x)
        {
            this.x = _x;
            this.y = 0;
        }

        public Complex(double _x, double _y)
        {
            this.x = _x;
            this.y = _y;
        }


        public static explicit  operator Complex(double _x)
        {
            return new Complex(_x);
        }

        public static bool  operator == (Complex lhs , Complex rhs)
        {
            return ((lhs.x == rhs.x) && (lhs.y == rhs.y));
        }

        public static bool  operator != (Complex lhs , Complex rhs)
        {
            return ((lhs.x != rhs.x) && (lhs.y != rhs.y));
        }

        public static Complex operator +(Complex lhs )
        {
            return lhs;
        }

        public static Complex operator -(Complex lhs )
        {
            return new Complex(-lhs.x, -lhs.y);
        }

        public static Complex  operator + (Complex lhs , Complex rhs)
        {
            return new Complex((lhs.x + rhs.x), (lhs.y + rhs.y));
        }

        public static Complex  operator - (Complex lhs , Complex rhs)
        {
            return new Complex((lhs.x - rhs.x), (lhs.y - rhs.y));
        }

        public static Complex  operator * (Complex lhs , Complex rhs)
        {
            return new Complex(((lhs.x*rhs.x) - (lhs.y*rhs.y)), ((lhs.x*rhs.y) + (lhs.y*rhs.x)));
        }

        public static Complex  operator / (Complex lhs , Complex rhs)
        {
            Complex complex = new Complex();
            double num;
            double num2;

            if (Math.Abs(rhs.y) < Math.Abs(rhs.x))
            {
                num = (rhs.y/rhs.x);
                num2 = (rhs.x + (rhs.y*num));
                complex.x = ((lhs.x + (lhs.y*num))/num2);
                complex.y = ((lhs.y - (lhs.x*num))/num2);
                return complex;
            }
            num = (rhs.x/rhs.y);
            num2 = (rhs.y + (rhs.x*num));
            complex.x = ((lhs.y + (lhs.x*num))/num2);
            complex.y = ((-lhs.x + (lhs.y*num))/num2);
            return complex;
        }
    }

    public class MathEx
    {
        public static double AbsComplex(Complex z)
        {
            double num2 = Math.Abs(z.x);
            double num3 = Math.Abs(z.y);
            double num      = (num2 > num3) ? num2 : num3;;
            double num4     = (num2 < num3) ? num2 : num3;

            if (num4 == 0)
                return num;

            double num5 = (num4/num);

            return (num*Math.Sqrt((1 + (num5*num5))));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="z"></param>
        /// <returns></returns>
        public static Complex Conj(Complex z )
        {
            return new Complex(z.x, -z.y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="z"></param>
        /// <returns></returns>
        public static Complex CSqr(Complex z  )
        {
            return new Complex(((z.x*z.x) - (z.y*z.y)), ((2*z.x)*z.y));
        }

        public static int RandomInteger(int N )
        {
            return MathEx.RndObject.Next(N);
        }
        public static double RandomReal()
        {
            return MathEx.RndObject.NextDouble();
        }

        public static double Sqr(double x)
        {
            return (x*x);
        }

        public double MachineEpsilon  = 0.0000000000000005;
        public double MaxRealNumber = 1.0E+300;
        public double MinRealNumber = 1.0E-300;
        private static Random RndObject = new Random();
    }
}

